#include "GameWorld.h"
#pragma comment(lib,"d3dx9.lib")

LPD3DXSPRITE SpriteHandler;

GameWorld::GameWorld(HINSTANCE hInstance, int FrameRate):Game(hInstance,FrameRate)
{
	startCheckingColli = false;
	mario=new Mario();
	viewport = NULL;
	resourceManager = new ResourceManager();
	quadTree = new QuadTree();
	font = new Font();
}

GameWorld::~GameWorld()
{
	delete mario;
	delete quadTree;
}

void GameWorld::InitGameWorld()
{

}

void GameWorld::LoadResources(LPDIRECT3DDEVICE9 d3ddv)
{
	srand((unsigned)time(NULL));
	D3DXCreateSprite(d3ddv,&SpriteHandler);
	HRESULT res = D3DXCreateSprite(d3ddv,&SpriteHandler);
	//-------------------------------------------------
	resourceManager -> LoadResource(d3ddv);

	quadTree -> InitGameObjectList("Data//object.txt");

	//Must load texture before deserializing 
	////////////////////////???Why can not load resource directly on quadTree
	map<int, GameObject *>::iterator iter;
	map<int, GameObject *> temp= quadTree -> GetMapGameObject();
	for(iter = temp.begin(); iter != temp.end(); ++iter)
	{
		//"switch" need value, not variables
		GameObjectType tempType = iter -> second -> GetType();
		switch (tempType)
		{
		case MarioPlayer:
			//intentionally do nothing
			break;
		case BrickNormalType:
			iter -> second ->  LoadResources(SpriteHandler, 
				&resourceManager -> brickNormalTexture);
			break;
		case BrickRedType:
			iter -> second ->  LoadResources(SpriteHandler, 
				&resourceManager -> brickNormalTexture);
			break;
		case BrickGoldType:
			iter -> second ->  LoadResources(SpriteHandler, 
				&resourceManager -> brickGoldTexture);
			break;
		case BrickHardType:
			iter -> second -> LoadResources(SpriteHandler, 
				&resourceManager -> brickHardTexture);
			break;
		case GroundGrassType:
			iter -> second -> LoadResources(SpriteHandler, 
				&resourceManager -> groundGrassTexture);
			break;
		case GoombaType:
			iter -> second -> LoadResources(SpriteHandler, 
				&resourceManager -> goombaTexture);
			break;
		case TurtleType:
			iter -> second -> LoadResources(SpriteHandler, 
				&resourceManager -> turtleTexture);
			break;
		case TubeHeadType:
			iter -> second -> LoadResources(SpriteHandler, 
				&resourceManager -> tubeHeadTexture);
			break;
		case TubeBodyType:
			iter -> second -> LoadResources(SpriteHandler, 
				&resourceManager -> tubeBodyTexture);
			break;
		case STree:case SFlower:case SCloud:
			iter -> second -> LoadResources(SpriteHandler, 
				&resourceManager -> scenaryTexture, tempType);
			break;
		}
	}

	quadTree -> SetMapGameObject(temp);
	//---------------------------------------------------------------------------

	//Deserialize quad tree
	quadTree -> Deserialize("Data//quadtree.txt");

	int mapWidthMin = quadTree -> GetMapWidth();
	if(mapWidthMin < GetScreenWidth())
		mapWidthMin = GetScreenWidth();
	int mapHeightMin = quadTree -> GetMapHeight();
	if(mapHeightMin < GetScreenHeight())
		mapHeightMin = GetScreenHeight();

	viewport = new ViewPort(D3DXVECTOR2(mario -> GetPosition().x - GetScreenWidth()/2, mario -> GetPosition().y - GetScreenHeight()/2),
		GetScreenWidth(), GetScreenHeight(), 
		mapWidthMin,
		mapHeightMin);

	//loading mario's resources must go after initializing game object list in quadtree (define position of mario).
	mario -> LoadResources(SpriteHandler);
}

void GameWorld::Update(int Delta)
{
	//update quadtree for drawing
	quadTree -> UpdateVectorObject(quadTree -> GetRootNode(), ViewPort::GetBound(), true);

	float X1 = viewport -> getLeft(),  X2 = viewport -> getRight();
	for(size_t i=0; i < quadTree -> VectorCollisionObject.size(); ++i)
	{
		if(((MovableObject*)quadTree -> VectorCollisionObject.at(i))->isMovableObj())
		{
			int tempX1 = ((MovableObject*)quadTree -> VectorCollisionObject.at(i))->GetLeftStop();
			int tempX2 = ((MovableObject*)quadTree -> VectorCollisionObject.at(i))->GetRightStop();
			if(tempX1 < X1) X1 = tempX1;
			if(tempX2 > X2) X2 = tempX2;
		}
	}

	//update quadtree for checking collision
	QRectangle bound = QRectangle( X1,
		ViewPort::GetBound().GetY() - COLLISION_SIZE,
		X2 - X1, 
		ViewPort::GetBound().GetHeight() + 2 * COLLISION_SIZE);
	quadTree -> UpdateVectorObject(quadTree -> GetRootNode(), bound, false);

	//mario is in the center of the screen
	viewport -> Move(D3DXVECTOR2(mario -> GetPosition().x - GetScreenWidth()/2, 
		mario -> GetPosition().y - GetScreenHeight()/2)); 

	mario -> Update(Delta, quadTree -> VectorCheckingColliObject, bound);

	//just update the objects in and near Viewport's bounding box
	for(size_t i=0; i < quadTree -> VectorCheckingColliObject.size(); ++i)
	{
		if((quadTree -> VectorCheckingColliObject[i])->isMovableObj())
			((MovableObject*) (quadTree -> VectorCheckingColliObject[i])) -> Update(Delta, quadTree -> VectorCheckingColliObject, bound);
		else ((StaticObject*) (quadTree -> VectorCheckingColliObject[i])) -> Update(Delta);
	}
}

void GameWorld::RenderFrame(LPDIRECT3DDEVICE9 d3ddv)
{
	SpriteHandler -> Begin(D3DXSPRITE_ALPHABLEND);
	d3ddv->ColorFill(BackBuffer, NULL, D3DCOLOR_XRGB(135, 206, 235));//sky color

	//render all
	for(size_t i=0; i< quadTree->VectorScenaryObject.size();++i)
	{
		//MessageBoxA(NULL,"render ","",0);

		quadTree->VectorScenaryObject.at(i) -> RenderFrame(BackBuffer,viewport);
	}
	for(size_t i=0; i< quadTree->VectorCollisionObject.size();++i)
	{
		quadTree->VectorCollisionObject.at(i) -> RenderFrame(BackBuffer,viewport);
		startCheckingColli = true;
	}

	mario->RenderFrame(BackBuffer,viewport);

	char buffer[20];
	_itoa_s(Score::score, buffer, 20,10);
	font -> DrawTextString(SpriteHandler, 0, 20, 100, 50, buffer);
	SpriteHandler->End();
}

void GameWorld::ProcessInput(LPDIRECT3DDEVICE9 d3ddv)
{
	if (Keyboard::GetInstance() -> IsKeyDown(DIK_RIGHT))
		mario->Right();
	else if (Keyboard::GetInstance() -> IsKeyDown(DIK_LEFT))
		mario->Left();
	else
		mario->Reset();
}

//continous
void GameWorld::OnKeyDown(int KeyCode)
{
	/*
	switch (KeyCode)
	{
	case DIK_UP:
	mario->Jump();

	break;
	}*/
}